<?php


require_once(dirname(__FILE__)."/../common/log.php");
require_once(dirname(__FILE__)."/../common/defines.php");
require_once(dirname(__FILE__)."/redis.config.php");


class RedisUtils
{
    private $options =
    [
        'host'        => REDIS_HOST,
        'port'        => REDIS_PORT,
        'password'    => REDIS_PWD,
        'select'      => 0,
        'timeout'     => 3,
        'expire'      => 0,
        'persistent'  => false,
        'prefix'      => '',
        'tag_prefix'  => 'tag:',
        'serialize'   => [],
    ];
    private $connect  = NULL;
    private $lock     = [];//互斥锁


    public function __construct(array $options = [])
    {
        if (!empty($options))
        {
            $this->options = array_merge($this->options, $options);
        }

        try
        {
            $this->connect  = new \Redis();
            $this->connect->connect($this->options['host'], $this->options['port']);
            $this->connect->auth($this->options['password']);
            $this->connect->select($this->options['select']);
        }
        catch (Exception $e)
        {
            $this->connect  = NULL;

            loge($e->getMessage());
        }        
    }

    public function __destruct()
    {
        try
        {
            //释放所有锁
            foreach ($this->lock as $key => $val)
            {
                $this->connect->del($key);
            }
            
            $this->connect->close();  
        }
        catch (Exception $e)
        {
            loge($e->getMessage());
        } 
    }

    public function select($db)
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {
            $this->connect->select($db);

            return SUCCESS;
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }            
    }

    public function lock($key, $ttl = 60)
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {        
            if (isset($this->lock[$key]))
            {
                return FAILURE;
            }

            do
            {
                $ret  = $this->try_lock($key, $ttl);
                if (empty($ret))
                {
                    usleep(10);
                }
            } while (empty($ret));

            return SUCCESS;
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }
    }

    public function try_lock($key, $ttl = 60)
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {        
            if (isset($this->lock[$key]))
            {
                return FAILURE;
            }

            $ret  = $this->connect->setnx($key, 1);
            if (!empty($ret))
            {
                $this->lock[$key]  = 1;
                $this->connect->expire($key, $ttl);
            }

            return $ret;
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }      
    }

    public function unlock($key)
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {        
            unset($this->lock[$key]);
            $this->connect->del($key);

            return SUCCESS;
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }        
    }

    public function ttl($key)
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {
            return $this->connect->ttl($key);
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }            
    }

    public function expire($key, $ttl)
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {
            return $this->connect->expire($key, $ttl);
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }            
    }

    public function exists($key)
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {
            return $this->connect->exists($key);
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }            
    }

    public function del($key)
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {
            return $this->connect->del($key);
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }            
    }

    public function keys($pattern)
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {
            return $this->connect->keys($pattern);
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }            
    }

    public function set($key, $val)
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {
            $this->connect->set($key, $val);

            return SUCCESS;
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }            
    }

    public function setex($key, $ttl, $val)
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {
            $this->connect->setex($key, $ttl, $val);

            return SUCCESS;
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }            
    }

    public function setnx($key, $val, $ttl = '')
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {
            $ret  = $this->connect->setnx($key, $val);
            
            if ($ttl !== '')
            {
                $ret  = $this->connect->expire($key, $ttl);
            }

            return $ret;
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }            
    }

    public function get($key)
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {
            return $this->connect->get($key);
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }            
    }

    public function incrby($key, $value, $ttl = '')
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {
            $ret  = $this->connect->incrby($key, $value);
            
            if ($ttl !== '')
            {
                $this->connect->expire($key, $ttl);
            }

            return $ret;
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }            
    } 

    public function decrby($key, $value, $ttl = '')
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {
            $ret  = $this->connect->decrby($key, $value);
            
            if ($ttl !== '')
            {
                $this->connect->expire($key, $ttl);
            }

            return $ret;
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }            
    } 

    public function sadd($key, $value, $ttl = '')
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {
            $ret  = $this->connect->sadd($key, $value);
            
            if ($ttl !== '')
            {
                $this->connect->expire($key, $ttl);
            }

            return $ret;
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }            
    }   

    public function smembers($key)
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {           
            return $this->connect->smembers($key);
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }            
    }   

    public function zadd($key, $score, $value, $ttl = '')
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {
            $ret  = $this->connect->zadd($key, $score, $value);
            
            if ($ttl !== '')
            {
                $this->connect->expire($key, $ttl);
            }

            return $ret;
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }            
    }   

    public function zrem($key, $field)
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {           
            return $this->connect->zrem($key, $field);
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }            
    }   

    public function zcard($key)
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {           
            return $this->connect->zcard($key);
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }            
    }   

    public function zscore($key, $field)
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {           
            return $this->connect->zscore($key, $field);
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }            
    }   

    public function zrank($key, $field)
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {           
            return $this->connect->zrank($key, $field);
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }            
    }   

    public function zincrby($key, $value, $field)
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {           
            return $this->connect->zincrby($key, $value, $field);
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }            
    }   

    public function zrangebyscore($key, $min, $max, $extra = [])
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {           
            return $this->connect->zrangebyscore($key, $min, $max, $extra);
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }            
    }   

    public function llen($key)
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {
            return $this->connect->llen($key);
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }            
    }   

    public function lpop($key)
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {
            return $this->connect->lpop($key);
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }            
    }   

    public function rpush($key, $value, $ttl = '')
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {
            $ret  = $this->connect->rpush($key, $value);
            
            if ($ttl !== '')
            {
                $this->connect->expire($key, $ttl);
            }

            return $ret;
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }            
    }   

    public function lrange($key, $start, $end)
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {
            return $this->connect->lrange($key, $start, $end);
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }            
    }   

    public function hset($key, $field, $value, $ttl = '')
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {
            $ret  = $this->connect->hset($key, $field, $value);
            
            if ($ttl !== '')
            {
                $this->connect->expire($key, $ttl);
            }

            return $ret;
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }            
    }   

    public function hsetnx($key, $field, $value, $ttl = '')
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {
            $ret  = $this->connect->hsetnx($key, $field, $value);
            
            if (!empty($ret))
            {
                $this->connect->expire($key, $ttl);
            }

            return $ret;
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }            
    }   

    public function hget($key, $field)
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {
            return $this->connect->hget($key, $field);
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }            
    }   

    public function hdel($key, $field)
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {
            return $this->connect->hdel($key, $field);
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }            
    }   

    public function hlen($key)
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {
            return $this->connect->hlen($key);
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }            
    }   

    public function hkeys($key)
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {
            return $this->connect->hkeys($key);
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }            
    }   

    public function hvals($key)
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {
            return $this->connect->hvals($key);
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }            
    }   

    public function hgetall($key)
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {
            return $this->connect->hgetall($key);
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }            
    }   

    public function hincrby($key, $field, $value, $ttl = '')
    {
        if ($this->connect == NULL)
        {
            return FAILURE;
        }

        try
        {
            $ret  = $this->connect->hincrby($key, $field, $value);
            
            if ($ttl !== '')
            {
                $this->connect->expire($key, $ttl);
            }

            return $ret;
        }
        catch (Exception $e)
        {
            loge($e->getMessage());

            return FAILURE;
        }            
    }   
}
